//
//  AIChatManager.m
//  Mia
//
//  Created by Vill on 2024/1/20.
//

#import "AIChatManager.h"
#import "GCDAsyncSocket.h"

//自动重连次数
NSInteger autoConnectCount = TCP_AutoConnectCount;

@interface AIChatManager ()<GCDAsyncSocketDelegate>
//初始化聊天
@property (strong , nonatomic) GCDAsyncSocket *chatSocket;
//所有的代理
@property (nonatomic, strong) NSMutableArray *delegates;
//心跳定时器
@property (nonatomic, strong) NSTimer *heartBeat;
//发送心跳次数
@property (nonatomic, assign) NSInteger senBeatCount;
//数据缓存
@property (nonatomic, strong) NSMutableData *buffer;

@end

@implementation AIChatManager

- (NSMutableData *)buffer{
    if(!_buffer) {
        _buffer = [NSMutableData data];
    }
    return _buffer;
}

//  初始化心跳
- (void)initHearBeat{
    dispatch_main_async_safe(^{
        [self destoryHeartBeat];
        __weak typeof (self) weakSelf=self;
        //心跳设置为3分钟，NAT超时一般为5分钟
        weakSelf.heartBeat = [NSTimer scheduledTimerWithTimeInterval:TCP_BeatDuration repeats:YES block:^(NSTimer * _Nonnull timer) {
            NSLog(@"heart");
            //和服务端约定好发送什么作为心跳标识，尽可能的减小心跳包大小
            //发送心跳
            AIChatModel *model = [AIChatModel new];
            model.token = [AIUserInfoManager shareManager].userInfo.token;
            model.chatType = @"PING";
            model.chatNumber = [[NSString getCurrentDateTime:1] integerValue];
            [self sendMessage:model timeOut:-1 tag:1];
        }];
        [[NSRunLoop currentRunLoop] addTimer:weakSelf.heartBeat forMode:NSRunLoopCommonModes];
        
    });
}

//  取消心跳
- (void)destoryHeartBeat{
    __weak typeof (self) weakSelf=self;
    dispatch_main_async_safe(^{
        if (weakSelf.heartBeat) {
            [weakSelf.heartBeat invalidate];
            weakSelf.heartBeat = nil;
        }
    });
}

- (NSMutableArray *)delegates{
    if (!_delegates) {
        _delegates = [NSMutableArray array];
    }
    return _delegates;
}

#pragma mark - 初始化聊天handler单例
+ (instancetype)shareInstance{
    static AIChatManager *handler = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        handler = [[AIChatManager alloc]init];
    });
    return handler;
}

- (instancetype)init{
    if (self = [super init]) {
        //将handler设置成接收TCP信息的代理
        _chatSocket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        //设置默认关闭读取
        [_chatSocket setAutoDisconnectOnClosedReadStream:NO];
        //默认状态未连接
        _connectStatus = SocketConnectStatus_UnConnected;
    }
    return self;
}

#pragma mark - 连接服务器端口
- (void)connectServerHost{
    NSError *error = nil;
    [_chatSocket connectToHost:TCP_Host onPort:TCP_Port error:&error];
    if (error) {
        NSLog(@"----------------连接服务器失败----------------");
    }else{
        NSLog(@"----------------连接服务器成功----------------");
    }
}

#pragma mark - 添加代理
- (void)addDelegate:(id<AIChatManagerDelegate>)delegate delegateQueue:(nullable dispatch_queue_t)queue{
    if (![self.delegates containsObject:delegate]) {
        [self.delegates addObject:delegate];
    }
}

#pragma mark - 移除代理
- (void)removeDelegate:(id<AIChatManagerDelegate>)delegate{
    [self.delegates removeObject:delegate];
}

- (void)sendMessageWithDic:(NSDictionary *)dic timeOut:(NSUInteger)timeOut tag:(long)tag{
    id jsonData = [NSData dicToData:dic];
    if ([jsonData isKindOfClass:[NSError class]]) {
        NSLog(@"数据转data失败______%@",jsonData);
        return;
    } else if ([jsonData isKindOfClass:[NSData class]]) {
        NSString *jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
        NSData *messageData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
        // 计算消息内容的长度
        uint32_t length = CFSwapInt32HostToBig((uint32_t)messageData.length);
        // 创建一个可变的数据容器，用于存储长度字段和消息内容
        NSMutableData *data = [NSMutableData dataWithCapacity:messageData.length + 4];
        // 添加长度字段
        [data appendBytes:&length length:sizeof(length)];
        // 添加消息内容
        [data appendData:messageData];
        [_chatSocket writeData:data withTimeout:timeOut tag:tag];
    } else {
        NSLog(@"数据转data失败+++++++");
    }
}

#pragma mark - 发送消息
- (void)sendMessage:(AIChatModel *)chatModel timeOut:(NSUInteger)timeOut tag:(long)tag{
    // 将模型对象转换为字典或 JSON 数据
    NSDictionary *modelDict = [chatModel mj_keyValues];
    id jsonData = [NSData dicToData:modelDict];
    if ([jsonData isKindOfClass:[NSError class]]) {
        NSLog(@"数据转data失败______%@",jsonData);
        return;
    } else if ([jsonData isKindOfClass:[NSData class]]) {
        NSString *jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
        NSData *messageData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
        // 计算消息内容的长度
        uint32_t length = CFSwapInt32HostToBig((uint32_t)messageData.length);
        // 创建一个可变的数据容器，用于存储长度字段和消息内容
        NSMutableData *data = [NSMutableData dataWithCapacity:messageData.length + 4];
        // 添加长度字段
        [data appendBytes:&length length:sizeof(length)];
        // 添加消息内容
        [data appendData:messageData];
        [_chatSocket writeData:data withTimeout:timeOut tag:tag];
    } else {
        NSLog(@"数据转data失败+++++++");
    }
}

#pragma mark - 主动断开连接
- (void)executeDisconnectServer{
    //更新sokect连接状态
    _connectStatus = SocketConnectStatus_UnConnected;
    [self disconnect];
}

#pragma mark - 连接中断
- (void)serverInterruption{
    //更新soceket连接状态
    _connectStatus = SocketConnectStatus_UnConnected;
    [self disconnect];
}

- (void)disconnect{
    //断开连接
    [_chatSocket disconnect];
    //未接收到服务器心跳次数,置为初始化
    _senBeatCount = 0;
    //自动重连次数 , 置为初始化
    autoConnectCount = TCP_AutoConnectCount;
}

#pragma mark - 发送心跳
- (void)sendBeat{
    //已经连接
    _connectStatus = SocketConnectStatus_Connected;
    //定时发送心跳开启
    [self initHearBeat];
}

/**********************************************delegate*********************************************************/
#pragma mark - 接收到消息
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
    // 将接收到的数据添加到缓存区中
    [self.buffer appendData:data];
    // 如果缓存区中的数据长度小于 4，说明没有读取到完整的消息头，返回
    if (self.buffer.length < 4) {
      [sock readDataWithTimeout:-1 tag:0];
      return;
    }
    // 从已接收的数据中读取长度字段(前4字节)
    NSData *lengthData = [self.buffer subdataWithRange:NSMakeRange(0, 4)];
    // 将长度字段转换为整数
    uint32_t length;
    [lengthData getBytes:&length length:sizeof(length)];
    length = ntohl(length);// !如果发送方和接收方所在的机器字节序不同，需要进行字节序转换
    // 判断已接收的数据是否包含完整的有效数据
    if (self.buffer.length >= (4 + length)) {
        // 提取有效数据
        NSRange range =NSMakeRange(4, length);
        NSData *validData = [self.buffer subdataWithRange:range];
        // 在这里处理有效数据
        NSString *contentString = [[NSString alloc] initWithData:validData encoding:NSUTF8StringEncoding];
        if (contentString) {
            // 处理接收到的完整消息数据
            [self handleMessageData:contentString];
        }
        // 移除已处理的数据
        [self.buffer replaceBytesInRange:NSMakeRange(0, (4 + length)) withBytes:NULL length:0];
        NSLog(@"------ 接收到反馈消息--------");
    }else {
        // 数据不完整，继续等待接收
        NSLog(@"数据不完整 ----- 继续接收");
        // 继续读取数据
        [sock readDataWithTimeout:-1 tag:tag];
    }
}

- (void)handleMessageData:(NSString *)messageData {
    // 处理接收到的完整消息数据，例如将其反序列化为模型对象等
    NSLog(@"************** Received message data: %@", messageData);
    AIResponse *response = [AIResponse mj_objectWithKeyValues:messageData];
    if (response.success == false){
        for (id<AIChatManagerDelegate>delegate in self.delegates) {
            if ([delegate respondsToSelector:@selector(didReceiveMessageWithErrorData:)]) {
                [delegate didReceiveMessageWithErrorData:response];
            }
        }
    }else{
        if ([response.data strHasValue]){
            NSString *jsonString = [AIAESUtil aesDecrypt:response.data];
            NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
            NSError *error;
            NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
            if (error == nil) {
                AIChatResponseContentModel *contentModel = [AIChatResponseContentModel mj_objectWithKeyValues:dic];
                for (id<AIChatManagerDelegate>delegate in self.delegates) {
                    if ([delegate respondsToSelector:@selector(didReceiveMessage:withChatModel:)]) {
                        [delegate didReceiveMessage:response withChatModel:contentModel];
                    }
                }
            }else{
                NSLog(@"报错了--- ");
            }
        }
    }
}

#pragma mark - 写入数据成功 , 重新开启允许读取数据
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{
    [self.chatSocket readDataWithTimeout:-1 tag:tag];
}

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{
    [_chatSocket readDataWithTimeout:-1 tag:1];
    [self sendBeat];
}

#pragma mark - TCP已经断开连接
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
    //如果是主动断开连接
    if (_connectStatus == SocketConnectStatus_DisconnectByUser) return;
    //置为未连接状态
    _connectStatus  = SocketConnectStatus_UnConnected;
    //自动重连
    if (autoConnectCount) {
        [self connectServerHost];
        NSLog(@"-------------剩余%ld次重连--------------",(long)autoConnectCount);
        autoConnectCount -- ;
    }else{
        NSLog(@"----------------重连次数已用完------------------");
    }
}

#pragma mark - 发送消息超时
- (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag elapsed:(NSTimeInterval)elapsed bytesDone:(NSUInteger)length{
    //此处进行数据库更新消息处理
    //发送超时消息分发
    for (id<AIChatManagerDelegate> delegate in self.delegates) {
        if ([delegate respondsToSelector:@selector(sendMessageTimeOutWithTag:)]) {
            [delegate sendMessageTimeOutWithTag:tag];
        }
    }
    return -1;
}


@end
